/*
 * CGetHostByName.cpp
 *
 *  Created on: 2023年3月18日
 *      Author: Administrator
 */

#include "include/CGetHostByName.h"

#include <stdio.h>
#include <string.h>
#include <QThreadPool>
#include <QDebug>
#include <functional>
#include <thread>

BASENET_BEGIN_NAMESPACE

	// 域名对应IP
MAP<string, string> CGetHostByName::m_hostAndNameMap;
	// 当前已开线程计数
int CGetHostByName::m_currentThreadCount = 0;
// 互斥锁
QMutex CGetHostByName::m_lock;

extern "C"{

// 兼容c方法
const char * gethostbyname_qg (const char *name, int timeOutMs)
{
	CGetHostByName app;
	string ip = app.getHostName(name, timeOutMs);
	if(ip.empty()){
		return NULL;
	}
	char *ipBuf = (char *)malloc(ip.size() + 1);
	memset(ipBuf, 0x00, ip.size() + 1);
	strncpy(ipBuf, ip.c_str(), ip.size());
	return ipBuf;
}

}



// 初始化mongoose库中的通用回调
void CGetHostByName::initMongoose()
{
	if(!mongoose_gethostbyname){
		mongoose_gethostbyname = gethostbyname_qg;
	}

}

CGetHostByName::CGetHostByName()
{
	// TODO Auto-generated constructor stub

}

CGetHostByName::~CGetHostByName() = default;

// 线程获取IP
void* CGetHostByName::__threadGetHostName(void* data)
{
	string url = (char*)data;
	delete[] data;
	data = nullptr;


	struct hostent *host = gethostbyname(url.c_str());
	if(!host){
		m_lock.lock();
        m_currentThreadCount--;
        m_lock.unlock();
		return NULL;
	}

	struct in_addr in;       // 报错：char* 类型的值不能用于初始化in_addr* 类型的实体
    memcpy((char *) &in.s_addr, host->h_addr, host->h_length);
	string ip = inet_ntoa(in);
    qDebug("%s\n",ip.c_str());

	m_lock.lock();
	m_hostAndNameMap[url] = ip;
	m_currentThreadCount--;
    m_lock.unlock();

	return NULL;
}

// 获取主机地址
string CGetHostByName::getHostName(const string &url, int timeOutMs)
{
	if(url.empty()){
		return "";
	}

	m_lock.lock();

	if(m_hostAndNameMap.find(url) != m_hostAndNameMap.end()){
		// 已保存了主机IP
		string ip = m_hostAndNameMap[url];
		m_hostAndNameMap.erase(url);
        m_lock.unlock();
		return ip;
	}

	if(m_currentThreadCount > 3){
        m_lock.unlock();
		return "";
	}
	m_currentThreadCount++;
	// 开启线程获取ip
	char *urlBuf = new char[url.size() + 1];
	memset(urlBuf, 0x00, url.size() + 1);
	strncpy(urlBuf, url.c_str(), url.size());

    std::thread t(__threadGetHostName, urlBuf);
    t.detach();


    m_lock.unlock();

	while(true){

		m_lock.lock();

		if(m_hostAndNameMap.find(url) != m_hostAndNameMap.end()){
			// 已保存了主机IP
			string ip = m_hostAndNameMap[url];
			m_hostAndNameMap.erase(url);
            m_lock.unlock();
			return ip;
		}

        m_lock.unlock();

		if(timeOutMs <= 0){
            m_lock.unlock();
			break;
        }
        std::this_thread::sleep_for(std::chrono::milliseconds(10000)); // 延时10毫秒
		timeOutMs -= 10;
	}

	return "";

}


// 获取主机地址
string CGetHostByName::getHostByName(const string &url, int timeOutMs)
{
	string host = url;
	if(!host.empty() && host.find("://") != host.npos){
		int pos = host.find("://");
		pos+=3;
		if(pos < host.size()){
			host = host.substr(pos);
		}
	}
	if(!host.empty() && host.find("/") != host.npos){
		int pos = host.find("/");
		if(pos < host.size()){
			host = host.substr(0,pos);
		}
	}
	CGetHostByName app;
	return app.getHostName(host, timeOutMs);
}

BASENET_END_NAMESPACE
